/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
class Controlflow {
    public static final double NUM_SETIME_CONST = 1_000_000.0;
    public static final int NUM_LOOP_COUNT_CONST = 80;
    public static boolean inDebug = false;
    public static void debuglog(String str) {
        if (inDebug) {
            System.out.println(str);
        }
    }
    public static double currentTimestamp13() {
        return System.nanoTime() / NUM_SETIME_CONST;
    }

    public static int ack(int m, int n) {
        if (m == 0) {
            return n + 1;
        }
        if (n == 0) {
            return ack(m - 1, 1);
        }
        return ack(m - 1, ack(m, n - 1));
    }

    public static int fib(double n) {
        int a = 2;
        if (n < a) {
            return 1;
        }
        return fib(n - a) + fib(n - 1);
    }

    public static int tak(int x, int y, int z) {
        if (y >= x) {
            return z;
        }
        return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y));
    }
}
/*
 *  @State
 *  @Tags Jetstream2
 */
class Benchmark {
    public static void run() {
        int result = 0;
        int a1 = 5;
        int a2 = 3;
        double b1 = 17.0;
        int c1 = 3;
        int c2 = 2;
        int c3 = 1;

        for (int i = 3; i <= a1; i++) {
            result += Controlflow.ack(a2, i);
            result += Controlflow.fib(b1 + i);
            result += Controlflow.tak(c1 * i + c1, c2 * i + c2, i + c3);
//            Controlflow.debuglog("controlflow-recursive: i = " + i +  " result = " + result);
        }

        int expected = 57775;
        if (result != expected) {
            throw new Error("ERROR: bad result: expected " + expected + " but got " + result);
        }
    }
    /**
     * @Benchmark
     */
    public static void addRunLoop(){
        double startTime = Controlflow.currentTimestamp13();
        for (int i = 0; i < Controlflow.NUM_LOOP_COUNT_CONST; i++) {
            double startTimeInLoop = Controlflow.currentTimestamp13();
            run();
            double endTimeInLoop = Controlflow.currentTimestamp13();
//            Controlflow.debuglog("controlflow-recursive: ms = " + (endTimeInLoop - startTimeInLoop) + " i = " + i);
        }
        double endTime = Controlflow.currentTimestamp13();
        System.out.println("controlflow-recursive: ms = " + (endTime - startTime));
    }

    public static void main(String[] args) {
        addRunLoop();
    }
}
